/*
* Copyright 2010 Pavel Kozhin 
*
* Licensed under the Apache License, Version 2.0 (the "License"); 
* you may not use this file except in compliance with the License. 
* You may obtain a copy of the License at 
* 
* http://www.apache.org/licenses/LICENSE-2.0
* 
* Unless required by applicable law or agreed to in writing, software 
* distributed  under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
* See the License for the specific language governing permissions and 
* limitations under the License.
*
* Author: Pavel Kozhin.
*/

package org.bookmarksframework.util
{
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.IEventDispatcher;
	import flash.utils.Dictionary;
	
	import mx.core.UIComponentGlobals;
	import mx.core.mx_internal;
	import mx.managers.ISystemManager;
	
	use namespace mx_internal;
	
	[Mixin]
	public final class CallLater
	{
		public var listeningForFrame:Boolean = false;
		
		private static var _systemManager:ISystemManager;
		
		private var methodQueue:Array = [];
		
		private static var dictionary:Dictionary;
		
		public static function init(systemManager:ISystemManager):void
		{
			_systemManager = systemManager
			dictionary = new Dictionary();
		}
		
		public static function execute(method:Function, args:Array = null, frames:uint = 1, allowSuspend:Boolean = true):void
		{
			var listener:Function;
			var dispatcher:IEventDispatcher = new Sprite();
			dictionary[dispatcher] = true;
			
			listener = function(event:Event):void
			{
				if (UIComponentGlobals.callLaterSuspendCount > 0 && allowSuspend)
					return;
				
				if ((frames--) <= 0)
				{
					dispatcher.removeEventListener(Event.ENTER_FRAME, listener);
					delete dictionary[dispatcher];
					method.apply(null, args);
				}
			}
			
			dispatcher.addEventListener(Event.ENTER_FRAME, listener);
		}
		
		public static function execute2(method:Function, args:Array = null, frames:uint = 1, allowSuspend:Boolean = false):void
		{
			var listener:Function;
			var dispatcher:IEventDispatcher = _systemManager.stage;
			
			if (dispatcher)
			{
				listener = function(event:Event):void
				{
					if (allowSuspend && UIComponentGlobals.callLaterSuspendCount > 0)
						return;
					
					if ((frames--) <= 0)
					{
						dispatcher.removeEventListener(Event.ENTER_FRAME, listener);
						method.apply(null, args);
					}
				};
				dispatcher.addEventListener(Event.ENTER_FRAME, listener);
			}
		}
		
		public function execute(method:Function, args:Array = null):void
		{
			methodQueue.push({method:method, args:args});
			
			var sm:ISystemManager = _systemManager;
			if (sm && sm.stage)
			{
				if (!listeningForFrame)
				{
					sm.stage.addEventListener(Event.ENTER_FRAME, callLaterDispatcher);
					listeningForFrame = true;
				}
			}
		}
		
		private function callLaterDispatcher(event:Event):void
		{
			if (UIComponentGlobals.callLaterSuspendCount > 0)
				return;
			
			var sm:ISystemManager = _systemManager;
			if (sm && sm.stage && listeningForFrame)
			{
				sm.stage.removeEventListener(Event.ENTER_FRAME, callLaterDispatcher);
				listeningForFrame = false;
			}
			
			var queue:Array = methodQueue;
			methodQueue = [];
			
			var max:int = queue.length;
			var queuedObj:Object;
			for (var i:int = 0; i < max; i++)
			{
				queuedObj = queue[i];
				queuedObj.method.apply(null, queuedObj.args);
			}
		}
	}
}